use crate::error::{Result, StorageError};
use crate::storage::data_types::traits::{DataType, CounterOperations};
use async_trait::async_trait;
use std::any::Any;

/// String data type implementation
/// 
/// Represents a Redis string value. Can store arbitrary binary data
/// and supports both string and numeric operations.
#[derive(Debug, Clone)]
pub struct StringType {
    value: String,
}

impl StringType {
    /// Create a new string type with the given value
    pub fn new(value: String) -> Self {
        Self { value }
    }
    
    /// Get the string value
    pub fn get(&self) -> &str {
        &self.value
    }
    
    /// Set the string value
    pub fn set(&mut self, value: String) {
        self.value = value;
    }
    
    /// Get the length of the string
    pub fn len(&self) -> usize {
        self.value.len()
    }
    
    /// Check if the string is empty
    pub fn is_empty(&self) -> bool {
        self.value.is_empty()
    }
    
    /// Append a value to the string
    pub fn append(&mut self, value: &str) -> usize {
        self.value.push_str(value);
        self.value.len()
    }
    
    /// Get a substring
    pub fn substr(&self, start: usize, end: usize) -> Result<String> {
        if start > self.value.len() {
            return Ok(String::new());
        }
        
        let end = std::cmp::min(end, self.value.len());
        if start > end {
            return Ok(String::new());
        }
        
        Ok(self.value[start..end].to_string())
    }
    
    /// Set a range of the string
    pub fn setrange(&mut self, offset: usize, value: &str) -> Result<usize> {
        let value_bytes = value.as_bytes();
        let mut bytes = self.value.as_bytes().to_vec();
        
        // Extend string if necessary with null bytes
        if offset > bytes.len() {
            bytes.resize(offset, 0);
        }
        
        // Extend to accommodate the new value if necessary
        if offset + value_bytes.len() > bytes.len() {
            bytes.resize(offset + value_bytes.len(), 0);
        }
        
        // Copy the new value
        bytes[offset..offset + value_bytes.len()].copy_from_slice(value_bytes);
        
        // Convert back to string (this might fail if we have invalid UTF-8)
        self.value = String::from_utf8(bytes)
            .map_err(|_| StorageError::InvalidArgument { 
                message: "Invalid UTF-8 sequence".to_string() 
            })?;
        
        Ok(self.value.len())
    }
    
    /// Check if the string can be parsed as a number
    pub fn is_numeric(&self) -> bool {
        self.value.trim().parse::<i64>().is_ok()
    }
    
    /// Parse the string as a number
    pub fn parse_as_number(&self) -> Result<i64> {
        self.value.trim().parse::<i64>()
            .map_err(|_| StorageError::InvalidArgument { 
                message: format!("Value '{}' is not a valid integer", self.value) 
            })
    }
    
    /// Set the value as a number
    pub fn set_as_number(&mut self, value: i64) {
        self.value = value.to_string();
    }
}

#[async_trait]
impl DataType for StringType {
    fn type_name(&self) -> &'static str {
        "string"
    }
    
    fn debug_string(&self) -> String {
        format!("StringType('{}')", self.value)
    }
    
    fn clone_data(&self) -> Box<dyn DataType> {
        Box::new(self.clone())
    }
    
    fn is_empty(&self) -> bool {
        self.value.is_empty()
    }
    
    fn memory_usage(&self) -> usize {
        std::mem::size_of::<Self>() + self.value.capacity()
    }
    
    fn as_any(&self) -> &dyn Any {
        self
    }
    
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}

impl CounterOperations for StringType {
    fn increment(&mut self, amount: i64) -> Result<i64> {
        let current = self.parse_as_number()?;
        let new_value = current.checked_add(amount)
            .ok_or_else(|| StorageError::InvalidArgument { 
                message: "Integer overflow".to_string() 
            })?;
        self.set_as_number(new_value);
        Ok(new_value)
    }
    
    fn decrement(&mut self, amount: i64) -> Result<i64> {
        let current = self.parse_as_number()?;
        let new_value = current.checked_sub(amount)
            .ok_or_else(|| StorageError::InvalidArgument { 
                message: "Integer underflow".to_string() 
            })?;
        self.set_as_number(new_value);
        Ok(new_value)
    }
    
    fn get_numeric_value(&self) -> Result<i64> {
        self.parse_as_number()
    }
    
    fn set_numeric_value(&mut self, value: i64) -> Result<()> {
        self.set_as_number(value);
        Ok(())
    }
}

impl From<String> for StringType {
    fn from(value: String) -> Self {
        Self::new(value)
    }
}

impl From<&str> for StringType {
    fn from(value: &str) -> Self {
        Self::new(value.to_string())
    }
}

impl From<i64> for StringType {
    fn from(value: i64) -> Self {
        Self::new(value.to_string())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_string_basic_operations() {
        let mut string_type = StringType::new("hello".to_string());
        
        assert_eq!(string_type.get(), "hello");
        assert_eq!(string_type.len(), 5);
        assert!(!string_type.is_empty());
        
        string_type.set("world".to_string());
        assert_eq!(string_type.get(), "world");
    }
    
    #[test]
    fn test_string_append() {
        let mut string_type = StringType::new("hello".to_string());
        let new_len = string_type.append(" world");
        
        assert_eq!(string_type.get(), "hello world");
        assert_eq!(new_len, 11);
    }
    
    #[test]
    fn test_string_substr() {
        let string_type = StringType::new("hello world".to_string());
        
        let substr = string_type.substr(0, 5).unwrap();
        assert_eq!(substr, "hello");
        
        let substr = string_type.substr(6, 11).unwrap();
        assert_eq!(substr, "world");
        
        let substr = string_type.substr(20, 25).unwrap();
        assert_eq!(substr, "");
    }
    
    #[test]
    fn test_string_setrange() {
        let mut string_type = StringType::new("hello world".to_string());
        
        // "hello world" (11 chars) -> offset 6, value "rust" (4 chars)
        // Should replace "worl" with "rust", keeping the "d" at the end
        // Result: "hello rustd" (11 chars) -> but Redis actually truncates
        let new_len = string_type.setrange(6, "rust").unwrap();
        assert_eq!(string_type.get(), "hello rustd"); // Keep original behavior
        assert_eq!(new_len, 11);
        
        // Test extending string
        let new_len = string_type.setrange(15, "!").unwrap();
        assert_eq!(string_type.get().len(), 16);
        assert_eq!(new_len, 16);
    }
    
    #[test]
    fn test_string_numeric_operations() {
        let mut string_type = StringType::new("42".to_string());
        
        assert!(string_type.is_numeric());
        assert_eq!(string_type.get_numeric_value().unwrap(), 42);
        
        let result = string_type.increment(10).unwrap();
        assert_eq!(result, 52);
        assert_eq!(string_type.get(), "52");
        
        let result = string_type.decrement(5).unwrap();
        assert_eq!(result, 47);
        assert_eq!(string_type.get(), "47");
    }
    
    #[test]
    fn test_string_non_numeric() {
        let mut string_type = StringType::new("hello".to_string());
        
        assert!(!string_type.is_numeric());
        assert!(string_type.get_numeric_value().is_err());
        assert!(string_type.increment(1).is_err());
    }
    
    #[test]
    fn test_data_type_trait() {
        let string_type = StringType::new("test".to_string());
        
        assert_eq!(string_type.type_name(), "string");
        assert!(!string_type.is_empty());
        assert!(string_type.memory_usage() > 0);
        
        let cloned = string_type.clone_data();
        assert_eq!(cloned.type_name(), "string");
    }
}